import json
from typing import Any, List, Union, Dict

from core.BaseAgent import BaseAgent
from LlmModel.DoubaoModel.DoubaoModel import DoubaoModel
from utils.PromotionChecker import PromotionChecker
from utils.logger import get_logger

logger = get_logger("FormAnalyzerServiceService")


class FormAnalyzerServiceService(BaseAgent):
    """表单分析器"""

    def __init__(self):
        self.doubao_client = DoubaoModel()
        self.promotion_checker = PromotionChecker()  # 创建外包检查器实例

    def _is_form_like(self, text: str) -> bool:
        """
        判断文本是否为表单形式（检查前5个字段）
        :param text: 待检查的文本
        :return: 是否为表单形式
        """
        # 用户习惯直接复制粘贴，下面用户再给内容转成dict之前要把"请填写表单\n：" 这部分replace掉
        text = text.replace("请填写表单\n：", "")

        form_indicators = [
            "达人昵称", "达人主页链接", "品牌/产品名称", "产品品类",
            "推广周期", "投放形式", "报备图文价格", "报备视频价格",
            "折扣要求", "创作方向", "排竞要求", "寄样方式"
        ]

        count = sum(1 for indicator in form_indicators if indicator in text)
        return int(count >= 5)  # 如果有5个以上的表单字段，认为是表单形式

    def process(self, input_data: Any) -> Any:
        pass

    def _check_form_completeness(self, text: str) -> List[str]:
        """
        检查表单完整性并返回空的必填字段列表（每个元素为指定的差异信息名称）

        :param text: 用户输入的表单文本
        :return: 空的必填字段列表，元素格式如"达人昵称:"、"达人主页链接:"等
        """
        try:
            # 定义所有必填的差异信息名称（按用户指定顺序）
            required_fields = [
                "达人昵称",
                "达人主页链接",
                "品牌/产品名称",
                "产品品类",
                "推广周期",
                "投放形式",
                "报备图文价格",
                "报备视频价格",
                "折扣要求",
                "创作方向",
                "排竞要求",
                "寄样方式"
            ]

            # 预处理文本：统一将中文冒号转为英文冒号，便于分割
            processed_text = text.replace("：", ":")
            lines = processed_text.split('\n')

            # 提取用户输入中已存在的字段及其值（键为带冒号的字段名，值为字段值）
            user_fields = {}
            for line in lines:
                line = line.strip()
                if not line or ':' not in line:
                    continue
                # 分割字段名（带冒号）和值
                field_name_with_colon, field_value = line.split(':', 1)
                field_name_with_colon = field_name_with_colon.replace(" ","").split(".", 1)[1]
                field_value = field_value.strip()
                user_fields[field_name_with_colon] = field_value

            print("-------------------------33------------------------\n")
            print(user_fields)
            print("-------------------------33------------------------\n")

            # 检查必填字段中哪些是空的（值为空或字段不存在）
            empty_fields = []
            for field in required_fields:
                # 字段不存在于用户输入中，视为空
                if field not in user_fields:
                    empty_fields.append(field)
                # 字段存在但值为空，视为空
                elif not user_fields[field]:
                    empty_fields.append(field)

            return empty_fields

        except Exception as e:
            logger.error(f"检查表单完整性失败: {str(e)}")
            print(f"检查表单完整性失败: {str(e)}")

            # 异常时返回所有必填字段（视为全部缺失）
            return [
                "达人昵称",
                "达人主页链接",
                "品牌/产品名称",
                "产品品类",
                "推广周期",
                "投放形式",
                "报备图文价格",
                "报备视频价格",
                "折扣要求",
                "创作方向",
                "排竞要求",
                "寄样方式"
            ]

    async def _compare_forms(self, base_info: str, user_form: str) -> str:
        """
        比较两个表单的折扣要求差异------------------------------>这里比较的差异，只比较两个表单的折扣要求差异，应该是有15种差异
        """

        """
        先用大模型做差异判断，判断有没有差异，差异的内容是什么 （这个方法）
        然后再做差异的归因（流程种后面的方法）
        """

        try:
            # 提取基础表单折扣值
            base_discount = self._extract_discount(base_info)
            if base_discount is None:
                logger.error(f"无法从基础表单中提取折扣值: {base_info}")
                return "无法提取基础表单折扣值"

            # 提取用户表单折扣值
            user_discount = self._extract_discount(user_form)
            if user_discount is None:
                logger.error(f"无法从用户表单中提取折扣值: {user_form}")
                return "无法提取用户表单折扣值"

            # 比较折扣值
            if base_discount <= user_discount:
                return ""  # 符合要求，返回空字符串
            else:
                return f"折扣要求超出基础表单值。基础表单值为：{base_discount}%，用户表单值为：{user_discount}%"

        except Exception as e:
            logger.error(f"表单比较失败: {str(e)}")
            return f"表单比较失败: {str(e)}"

    async def get_forms_differ_unionDict(self, base_info: str, user_form: str,user_input: str,is_c2_mode:bool,is_submit:int,is_form:int,
                                         conversations: List[Dict[str, str]] = None ):
        """
        比较两个表单的差异，返回包含两类差异的复合字典
        返回结构说明：
        - negotiable：list[str]，原7个可议价原因（值为空=无差异）
        - non_negotiable：list[str]，新增8个不可议价原因（值为空=无差异）
        - has_non_negotiable：bool，是否存在不可议价差异（True=有，需优先处理）
        """
        try:
            # 1. 定义两类原因的字段映射（原7个+新增8个）
            key_reasons_mapping = """
                            【可议价原因（共7个，可讨价还价）】
                            1. 返点不满足 → 严格对应"折扣要求"字段
                            2. 排竞时长不满足 → 严格对应"排竞要求"字段  
                            3. 档期不满足 → 严格对应"推广周期"字段
                            4. 创作风格不符合 → 严格对应"创作方向"字段
                            5. 数据不保证 → 严格对应"可保阅读数据、可保互动数据"字段
                            """

            non_negotiable_mapping = """
               【不可议价原因（共9个，不可讨价还价，必须满足基础要求）】
                1. 账号异常 → 账号状态异常（如限流、警告、异常状态）
                2. 品牌有负面 → 品牌负面舆情（如负面新闻、口碑问题）
                3. 需求不匹配 → 合作需求不匹配（如需求不符合博主定位）
                4. 不接报备 → 不接受报备合作（如嫌报备流程麻烦）
                5. 不接非报备 → 只接受报备合作（如担心非报备违规）
                6. 不接该类产品 → 不接受某类产品（如不接医药保健品）
                7. 近期不接广 → 近期不接广告（如沉淀内容期）
                8. 场地不符合 → 场地条件不符合（如尺寸、安装问题）
                9. 无真人出镜 → 不接受真人出镜（如只做图文内容）
                            """

            # 准备对话上下文（用于不可议价原因判断）
            conversation_context = ""
            if conversations:
                # 只取最近几轮对话避免过长
                recent_conversations = conversations[-6:]  # 取最近3轮（6条消息）
                conversation_context = "对话记录：\n"
                for i, conv in enumerate(recent_conversations):
                    role = "用户" if conv.get("role") == "user" else "助手"
                    conversation_context += f"{role}: {conv.get('content', '')}\n"

            # 2. 构建比较提示词（修改：去掉原因4和5的检查）
            compare_prompt = f"""
                请严格比较以下两个表单的差异，分别识别"可议价原因"和"不可议价原因"：

                {key_reasons_mapping}
                {non_negotiable_mapping}

                基础表单（base_info）：
                {base_info}

                用户表单（user_form）：
                {user_form}



                # 核心判定规则（从"用户表单"到"可议价原因"和"不可议价原因"映射关系）：

                ## 可议价原因判定（严格字段映射）：
                - 仅当对应字段存在明确差异时才判定为可议价原因
                - 返点不满足：严格比较"折扣要求"字段，用户折扣＜基础折扣→判定为原因1
                - 排竞不满足：严格比较"排竞要求"字段，用户排竞＜基础排竞→判定为原因2
                - 档期不满足：如果{is_c2_mode}为True并且{is_form}为1则严格比较基础表单与用户表单"推广周期"字段，用户周期不在基础周期内→判定为原因4（此项将由专门模块检查），如果is_form为那么就比较历史对话最后几轮对话、用户最后说的最后一句话{user_input}与基础表单比较查看是否时间在基础表单内，如果{is_c2_mode}为False则严格比较历史对话中或者用户当前对话{user_input}的"档期"字眼，看用户是否表明有档期。
                - 创作风格不符：严格比较"创作方向"字段，内容不一致→判定为原因5（此项将由专门模块检查）
                - 数据不保证：严格比较"可保阅读数据、可保互动数据"字段，用户数据＜基础数据→判定为原因6
                - 无差异的字段对应原因必须返回空字符串
                - 注意：原因4和原因5将由专门模块检查，请将这两个原因的值设为空字符串

                ## 不可议价原因判定（从对话和表单内容识别）：
                - 重点从对话和表单中识别不可议价的原因，如资质、合规、权限等问题
                - 重点从对话和表单中识别不可议价的原因
                - 账号异常：对话中提及账号异常、限流、警告等（如"账号最近被限流了"、"账号异常"）
                - 品牌有负面：对话中提及品牌负面、口碑问题等（如"品牌有负面新闻"、"舆论不好"）
                - 需求不匹配：对话中提及需求不符合、不匹配等（如"需求不太匹配"）
                - 不接报备：对话中明确表示不接报备合作（如"不接报备"、"报备太麻烦"）
                - 不接非报备：对话中明确表示只接报备合作（如"只接报备"、"非报备不接"）
                - 不接该类产品：对话中明确表示不接某类产品（如"医药保健品不接"）
                - 近期不接广：对话中表示近期不接广告（如"最近不接广"、"沉淀内容期"） 如果出现档期字眼、竞品字眼则不能归类为近期不接广
                - 场地不符合：对话中提及场地、尺寸等问题（如"场地大小不够"）
                - 无真人出镜：对话中表示不做真人出镜（如"不做真人出镜"）
                - 只要表单或对话中明确提及上述不可议价问题，就判定对应原因

                ## 特殊场景：（修改：特殊场景）
                - 语义匹配：包含关系视为一致（如"种草"与"单品种草"一致）
                - 格式差异忽略（如"35%"与"35"一致）
                - 必须严格遵循从"用户表单"到"可议价原因"和"不可议价原因"映射关系，不相关的差异不返回
                - 优先处理不可议价原因，因为这类差异必须满足

                # 输出要求（强制复合JSON，无多余内容）：
                - 根节点为字典，包含3个键："negotiable"、"non_negotiable"、"has_non_negotiable"；
                - "negotiable"：列表，长度为7（对应7个可议价原因），值为差异描述或空字符串；
                - "non_negotiable"：列表，长度为8（对应8个不可议价原因），值为差异描述或空字符串；
                - "has_non_negotiable"：布尔值，True=存在不可议价差异，False=无此类差异；
                - 无差异时对应位置为空字符串，必须包含全部元素，不可缺失。
                - 特别注意：原因4和原因5的值必须设为空字符串，这两个原因将由专门模块检查

                示例输出（non_negotiable列表有内容）：
                {{
                    "negotiable":["返点不满足：折扣要求不一致，基础值：35%，用户值：30%","","","","","",""],
                    "non_negotiable":["","样品检测缺失：表单中缺少CMA检测报告","","","","","",""],
                    "has_non_negotiable":true
                }}

                示例输出（non_negotiable列表无内容）：
                {{
                    "negotiable":["返点不满足：折扣要求不一致，基础值：35%，用户值：30%","","","","","",""],
                    "non_negotiable":["","","","","","","",""],
                    "has_non_negotiable":false
                }}
                """

            # 3.  调用大模型获取复合差异结果（不包含原因4和5）
            comparison = await self.doubao_client.generate_text(compare_prompt)
            comparison = comparison.strip()

            logger.info("差一点分析结果{}".format(comparison))

            # 4. 解析复合JSON（分离两类差异+状态）
            try:
                clean_comparison = comparison.replace("'", "\"").strip()
                result_dict = json.loads(clean_comparison)

                # 初始化默认结构（防止大模型返回缺失键）
                default_negotiable = [""] * 7
                default_non_negotiable = [""] * 8

                # 提取两类差异（用默认值兜底，避免键缺失）
                negotiable = result_dict.get("negotiable", default_negotiable)
                non_negotiable = result_dict.get("non_negotiable", default_non_negotiable)
                logger.info("negotiable结果{}".format(negotiable))
                logger.info("non_negotiable结果{}".format(non_negotiable))
                # 确保是列表类型且长度正确
                if not isinstance(negotiable, list) or len(negotiable) != 7:
                    negotiable = default_negotiable
                if not isinstance(non_negotiable, list) or len(non_negotiable) != 8:
                    non_negotiable = default_non_negotiable

                # 计算不可议价状态（只要non_negotiable有一个非空值，就是True）
                has_non_negotiable = any(bool(str(val).strip()) for val in non_negotiable)

            except json.JSONDecodeError:
                logger.error(f"无法解析复合差异JSON（格式错误）: {comparison[:50]}...")
                negotiable = [""] * 7
                non_negotiable = [""] * 8
                has_non_negotiable = False
            except Exception as e:
                logger.error(f"解析复合差异时发生异常: {str(e)}")
                negotiable = [""] * 7
                non_negotiable = [""] * 8
                has_non_negotiable = False

            # 5. 使用外包检查器检查原因4和5
            # 只有在需要时才进行外包检查
            if is_submit == 1 or is_form == 1:
                promotion_result = await self.promotion_checker.check_promotion_period(base_info, user_form, user_input)
                creation_result = await self.promotion_checker.check_creation_direction(base_info, user_form)

                # 处理推广周期检查结果
                if promotion_result is None:
                    # 一致：清空差异
                    negotiable[2] = None
                    logger.info("外包检查确认：推广周期一致，清空对应差异")
                else:
                    # 不一致：设置差异描述
                    negotiable[2] = promotion_result
                    logger.info(f"外包检查确认：推广周期不一致，差异：{promotion_result}")

                # 处理创作方向检查结果
                if creation_result is None:
                    # 一致：清空差异
                    negotiable[3] = None
                    logger.info("外包检查确认：创作方向一致，清空对应差异")
                else:
                    # 不一致：设置差异描述
                    negotiable[3] = creation_result
                    logger.info(f"外包检查确认：创作方向不一致，差异：{creation_result}")
            else:
                logger.info("跳过分包检查：is_submit={}, is_form={}".format(is_submit, is_form))

            # 6. 过滤掉空字符串，只保留有差异的描述
            filtered_negotiable = [item for item in negotiable if item and str(item).strip()]
            filtered_non_negotiable = [item for item in non_negotiable if item and str(item).strip()]

            # 7. 构建最终返回的复合字典
            final_result = {
                "negotiable": filtered_negotiable,  # 过滤后的可议价差异列表
                "non_negotiable": filtered_non_negotiable,  # 过滤后的不可议价差异列表
                "has_non_negotiable": has_non_negotiable  # 快速判断状态
            }
            logger.info("final_result结果{}".format(final_result))

            print("----------------------------------")
            print("最终差异结果（过滤空值）：")
            print(f"可议价差异：{final_result['negotiable']}")
            print(f"不可议价差异：{final_result['non_negotiable']}")
            print(f"是否存在不可议价差异：{final_result['has_non_negotiable']}")
            print("----------------------------------")

            return final_result["negotiable"], final_result["non_negotiable"], final_result["has_non_negotiable"]

        except Exception as e:
            logger.error(f"表单比较失败: {str(e)}")
            # 异常时返回结构完整的默认值
            return {
                "negotiable": [],
                "non_negotiable": [],
                "has_non_negotiable": False
            }

# if __name__ == '__main__':
#     formAnalyzerServiceService = FormAnalyzerServiceService()
#     res=formAnalyzerServiceService._check_form_completeness("宝子，我填好啦～\n1.达人昵称:美妆博主小雨\n2.达人主页链接:https://www.xiaohongshu.com/user/profile/5fb755d5000000000101e4c8\n3.品牌/产品名称:\n4.产品品类:美妆护肤\n5.推广周期:11月13日发布（12号有事排不开）\n6.投放形式:只能拍15秒短视频（长了粉丝没耐心），不做全肤质试色（我只有干皮粉丝）\n7.报备图文价格:15000元\n8.报备视频价格:28000元\n9.是否可以保价到次月:是\n10.折扣要求:30%（我这边最多只能给30%）\n11.创作方向:口红开箱（只拍包装和试色，不聊持久度）\n12.排竞要求:前14后15（前14天要接其他口红推广，没法空）\n13.寄样方式:品牌寄拍（包邮）\n14.达人鞋服尺码:无需\n15.免费展示套数及加价:最多2个色号，超1个加400元（多了试色太费时间）\n16.可保阅读数据:视频只能保8000播放（1.2万太高了）\n17.可保互动数据:点赞+评论≥300（转发没法保证）\n18.是否可以免费授权品牌信息流 6 个月？:最多授权3个月（6个月太长）\n19.是否可以免费授权品牌二剪及全平台传播（包括电商）6 个月？:可以授权，但抖音电商不行（我在抖音没开店）\n20.是否可以免费分发其他平台？:只同步小红书（抖音微博没运营）\n21.是否有特殊合作注意事项？:广告占比≤18%（太高粉丝会取关），脚本不能改（拍前确认好，改了要重拍）\n22.是否免费授权电商平台植入 6 个月？:不授权（怕影响粉丝信任）\n23.是否授权搜索引导6 个月？:可以授权\n24.是否授权带相关话题6 个月？:可以授权\n25.是否授权组件需求6 个月？:不授权（组件影响观看体验）\n26.是否授权引流需求6 个月？:可以授权\n27.达人账号资质:暂时没有《美妆类推广资质证书》（正在办理）\n28.样品检测报告:没准备CMA检测报告（品牌没说要啊）\n29.合规责任声明:还没签署合规声明（要先看内容）\n30.平台发布权限:没开通品牌合作人权限（粉丝还没到10万）\n31.售后责任承诺:不承诺协助售后（我这边没客服）\n32.发票开具类型:只能开增值税普通发票（专票要加税点）\n33.数据备案编号:没有平台备案编号（不知道要这个）\n34.可推广地域:只覆盖华东地区（其他地区没流量）")
#     print(res)
